// file:include/os/spinlock.h
// autor:jiang xinpeng
// time:2020.12.6
// copyright:(C) 2020-2050 by Jiang xinpeng. All rights reserved.

#ifndef OS_SPINLOCK_H
#define OS_SPINLOCK_H

#include <arch/atomic.h>
#include <arch/x86.h>

// spinlock struct
typedef struct spinlock
{
    atomic_t ato_lock; // 0 unlock 1 lock
} spinlock_t;

#define _SPIN_COUNT 100

// lock init
#define SPIN_LOCK_INIT_UNLOCK() \
    {                           \
        ATOMIC_INIT(0)          \
    }
#define SPIN_LOCK_INIT_LOCK() \
    {                         \
        ATOMIC_INIT(1)        \
    }
#define SPIN_LOCK_INIT() SPIN_LOCK_INIT_UNLOCK()

// creat lock
#define DEFINE_SPIN_LOCK_UNLOCK(name) spinlock_t name = SPIN_LOCK_INIT_UNLOCK()
#define DEFINE_SPIN_LOCK_LOCk(name) spinlock_t name = SPIN_LOCK_INIT_LOCK()
#define DEFINE_SPIN_LOCK(name) DEFINE_SPIN_LOCK_UNLOCK(name)

static inline void SpinLockInit(spinlock_t *name)
{
    AtomicSet(&name->ato_lock, 0);
}

static inline int SpinTryLock(spinlock_t *lock)
{
    return (!AtomicXCHG(&lock->ato_lock, 1));
}

// previous declaration
void TaskYield();

static inline void SpinLock(spinlock_t *lock)
{
    int i;

    // try lock
    do 
    {
        if (SpinTryLock(lock))
            return;
    }while(1);
}


static inline void SpinUnlock(spinlock_t *lock)
{
    AtomicSet(&lock->ato_lock, 0);
}

// spin lock and disable interrupt
static inline void SpinLockDisInterrupt(spinlock_t *lock)
{
    DisInterrupt();
    SpinLock(lock);
}

// spin unlock and enable interrupt
static inline void SpinUnlockEnInterrupt(spinlock_t *lock)
{
    SpinUnlock(lock);
    EnInterrupt();
}

#define SpinLockDisInterruptSave(lock,eflags) {eflags=InterruptDisableStore(); SpinLock(lock);}
#define SpinUnlockEnableInterruptRestore(lock,eflags) {SpinUnlock(lock);InterruptEnableRestore(eflags);}

static inline int SpinIsUnlock(spinlock_t *lock)
{
    return (!AtomicGet(&lock->ato_lock));
}

static inline int SpinIsLock(spinlock_t *lock)
{
    return AtomicGet(&lock->ato_lock);
}

#endif